home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-08-03 | 64.3 KB | 2,247 lines |
-
- /* Generated by Interface Builder */
-
- #import "defs.h"
- #import "Plot.h"
- #import <appkit/Button.h>
- #import <appkit/OpenPanel.h>
- #import <appkit/SavePanel.h>
- #import <appkit/Matrix.h>
- #import <appkit/Window.h> // added by pdhowell
- #import <appkit/Cell.h>
- #import <appkit/appkit.h>
- #import <objc/Storage.h>
- #import <math.h> /* for MAXFLOAT, etc. */
- #import <strings.h>
- #import <streams/streams.h>
- #import "ColumnSelectionHandler.h"
- #import "ErrorBarHandler.h"
- #import <defaults.h>
-
- /* The following routines are in auxil.m: */
- extern void computeNiceLinInc(float *, float *, float *);
- extern void computeNiceLogInc(float *, float *, float *);
-
- @implementation Plot
-
- - makeSomeScrollWindows
- {
- // the following lines exist only to initialize the ScrollWindows.....pdhowell
- NXSize minsize = {0.0,0.0};
-
- [lineMatrixWindow becomeScrollWindow];
- [symbolMatrixWindow becomeScrollWindow];
- [legendFormWindow becomeScrollWindow];
-
- [lineMatrixWindow setMinFrameSize:minsize];
- [symbolMatrixWindow setMinFrameSize:minsize];
- [legendFormWindow setMinFrameSize:minsize];
-
- return self;
- }
-
- + initialize
- {
- const NXDefaultsVector nxyplotDefaults = {
- { "colorOption", "NO"},
- { "colorPrinting", "NO"},
- { "cycleLineStyles", "NO"},
- { "opaqueBackground", "YES"},
- { NULL, NULL}
- };
-
- self = [[Object alloc] init];
- NXRegisterDefaults("nxyplot", nxyplotDefaults);
- return self;
- }
-
- - init
- {
- // Initialize variables here:
- nfilestotal = 0;
- ncurvestotal = 0;
- globaldatamin.x = MAXFLOAT;
- globaldatamin.y = MAXFLOAT;
- globaldatamax.x = -MAXFLOAT;
- globaldatamax.y = -MAXFLOAT;
- beepError = 0;
- backgroundcolor = NX_COLORWHITE;
- textcolor = NX_COLORBLACK;
- srandom(10); /* initialize for color selection */
- oldMin.x = 0.0;
- oldMin.y = 0.0;
- oldMax.x = 0.0;
- oldMax.y = 0.0;
- oldInc.x = 0.0;
- oldInc.y = 0.0;
- currentMin.x = 0.0;
- currentMin.y = 0.0;
- currentMax.x = 0.0;
- currentMax.y = 0.0;
- currentInc.x = 0.0;
- currentInc.y = 0.0;
-
- return self;
- }
-
- // Delete all data (free up the space that was malloc'ed)
- - removeAllFiles:sender
- {
- int n, j;
- datahunk *pdh;
- const char * generictitle = "NXYPLOT";
-
- if (nfilestotal == 0) {
- return self;
- }
-
- // Put up an alert panel. This method is called by a menu item and also
- // by the removeAndOpen method; only if it's called by the menu item
- // do we want to put up the alert panel.
- if (sender != self) {
- if (NXRunAlertPanel("Remove all", "Remove all files and clear plot",
- "OK", "Cancel", NULL) == NX_ALERTALTERNATE) {
- return self;
- }
- }
-
- for (n=nfilestotal-1; n>=0; n--) {
- pdh = (datahunk *)[datahunkArray elementAt:(unsigned)n];
- for (j = 0; j < pdh->ncurves; j++) {
- free( (void *)*(pdh->y+j) );
- }
- free( (void *)(pdh->y) );
- if (pdh->has_eybars) {
- for (j = 0; j < pdh->ncurves; j++) {
- free( (void *)*(pdh->ey+j) );
- }
- free( (void *)(pdh->ey));
- }
- free( (void *)(pdh->x) );
- if (pdh->has_exbars) {
- free( (void *)(pdh->ex));
- }
- free( (void *)(pdh->filename) );
- }
- [datahunkArray empty];
- [self adjustPanels:ncurvestotal :-1]; /* -1 is a special signal */
- nfilestotal = 0;
-
- [columnSelectionHandler removeAll:self];
-
- [errorBarHandler removeAll:self];
-
- [canvas display]; /* clear the canvas */
-
- [[canvas window] setTitle:generictitle];
-
- ncurvestotal = 0;
-
- // reset globaldatamin/max
- globaldatamin.x = MAXFLOAT;
- globaldatamin.y = MAXFLOAT;
- globaldatamax.x = -MAXFLOAT;
- globaldatamax.y = -MAXFLOAT;
-
- // clear xMin/Max/Inc and yMin/Max/Inc windows:
- [xMin setStringValue:"" at:0];
- [xMax setStringValue:"" at:0];
- [xInc setStringValue:"" at:0];
- [yMin setStringValue:"" at:0];
- [yMax setStringValue:"" at:0];
- [yInc setStringValue:"" at:0];
- srandom(10); /* initialize for color selection */
-
- oldMin.x = 0.0;
- oldMin.y = 0.0;
- oldMax.x = 0.0;
- oldMax.y = 0.0;
- oldInc.x = 0.0;
- oldInc.y = 0.0;
- currentMin.x = 0.0;
- currentMin.y = 0.0;
- currentMax.x = 0.0;
- currentMax.y = 0.0;
- currentInc.x = 0.0;
- currentInc.y = 0.0;
-
- return self;
- }
-
- // Remove all existing files and open a new one
- - removeAndOpen:sender
- {
- if (NXRunAlertPanel("New",
- "Remove all files, clear plot\nand open new file",
- "OK", "Cancel", NULL) == NX_ALERTALTERNATE) {
- return self;
- }
-
- [self removeAllFiles:self];
- [self open:self];
- return self;
- }
-
-
- - fixFileRemovalPanel:sender
- {
- int n;
- char title[80];
- NXCoord dy;
- int numrows, numcols;
- NXSize cellsize, intercell;
-
- // Fix up the filename matrix
- [fileRemovalMatrix getNumRows:&numrows numCols:&numcols];
- [fileRemovalMatrix getCellSize:&cellsize];
- [fileRemovalMatrix getIntercell:&intercell];
-
- [fileRemovalMatrix renewRows:nfilestotal cols:1];
- dy = (NXCoord)(nfilestotal - numrows) * (cellsize.height + intercell.height);
- for (n=0; n<nfilestotal; n++) {
- if (!strncmp([self filename:(unsigned)n], "pasteboard", 10))
- sprintf(title, "pasteboard");
- else
- sprintf(title, strrchr([self filename:(unsigned)n], '/') + 1);
- [[fileRemovalMatrix cellAt:n :0] setStringValue:title];
- }
- [fileRemovalMatrix sizeToCells];
- [fileRemovalMatrix moveBy:0.0 :-dy];
-
- // Fix up the buttons that go with the matrix of names
- [fileRemovalButtons getCellSize:&cellsize];
- [fileRemovalButtons getIntercell:&intercell];
- dy = (NXCoord)(nfilestotal - numrows) * (cellsize.height + intercell.height);
- [fileRemovalButtons renewRows:nfilestotal cols:1];
- [fileRemovalButtons sizeToCells];
- [fileRemovalButtons moveBy:0.0 :-dy];
- for (n=0; n<nfilestotal; n++) {
- [ [fileRemovalButtons cellAt:n :0] setState:0]; /* a safety play */
- }
-
- [fileRemovalPanel display];
-
- if (sender != self) {
- /* If this method is called from the menu, make the window key. */
- [fileRemovalPanel makeKeyAndOrderFront:self];
- }
-
- return self;
- }
-
-
- // Remove some existing files; the file removal is not hard, but correctly
- // updating the linestyle, symbolstyle, and legend matrices is harder.
- // Correctly handling the ColumnSelection and ErrorBar panels is even harder.
- - removeSomeFiles:sender
- {
- int n, i, j;
- int old_index = 0, current_index = 0;
- /* These integers point to the columns of the linestyle and symbolstyle
- * matrices as we run along updating the matrices. They also serve in
- * updating the curvecolors array.
- */
- datahunk *pdh;
- int *newlinestyles, *newsymbolstyles;
-
- if (nfilestotal == 0) {
- return self;
- }
-
- /* Figure out what the linestyle and symbolstyle matrices should look
- * like after the file removal process. We do it this way because simply
- * copying the columns of the matrices fails after the renewRows:cols:
- * message is sent to them.
- */
- newlinestyles = (int *)malloc(ncurvestotal * sizeof(int));
- newsymbolstyles = (int *)malloc(ncurvestotal * sizeof(int));
- for (n=0; n < nfilestotal; n++) {
- if ([[fileRemovalButtons cellAt:n :0] state] == 1) {
- /* Just bump the index if the file is to be deleted. */
- old_index += [self nCurves:n];
- }
- else {
- for (i=0; i < [self nCurves:n]; i++) {
- for (j=0; j < N_LINE_STYLES; j++) {
- if ([ [lineMatrix cellAt:j :old_index] state] == 1) {
- newlinestyles[current_index] = j;
- break;
- }
- }
- for (j=0; j < N_SYMBOL_STYLES; j++) {
- if ([ [symbolMatrix cellAt:j :old_index] state] == 1) {
- newsymbolstyles[current_index] = j;
- break;
- }
- }
- /* Update the curvecolors array: */
- curvecolors[current_index] = curvecolors[old_index];
- old_index++;
- current_index++;
- }
- }
- }
- /* We could do a realloc on curvecolors here, but not much would be saved. */
-
- /* Reset the running indices. */
- old_index = 0;
- current_index = 0;
-
- for (n=0; n < nfilestotal; n++) {
- /* Is the nth file marked for deletion? */
- if ([[fileRemovalButtons cellAt:n :0] state] == 1) { /* yes it is */
- pdh = (datahunk *)[datahunkArray elementAt:(unsigned)n];
- for (j = 0; j < pdh->ncurves; j++) {
- free( (void *)*(pdh->y+j) );
- }
- free( (void *)(pdh->y) );
- if (pdh->has_eybars) {
- for (j = 0; j < pdh->ncurves; j++) {
- free( (void *)*(pdh->ey+j) );
- }
- free( (void *)(pdh->ey));
- }
- free( (void *)(pdh->x) );
- if (pdh->has_exbars) {
- free( (void *)(pdh->ex));
- }
- free( (void *)(pdh->filename) );
- old_index += [self nCurves:n];
- }
- else {
- /* Column copying of the linestyle and symbolstyle matrices
- * is handled later. Do the legend form here.
- */
- for (j=0; j < [self nCurves:n]; j++) {
- [legendForm setStringValue:[legendForm stringValueAt:old_index]
- at:current_index];
- [legendForm drawCellAt:current_index];
- old_index++;
- current_index++;
- }
- }
- }
-
- /* Get rid of extraneous legendForm entries: */
- for (j=current_index; j<ncurvestotal; j++) {
- [legendForm removeEntryAt:j];
- }
- [legendForm sizeToFit];
- [ [legendForm window] display];
-
- /*
- * Do the ColumnSelectionHandler manipulation here, before nfilestotal
- * gets reset.
- */
- [columnSelectionHandler update:self];
- [errorBarHandler update:self];
-
- /* We put the datahunkArray manipulation here because the removeAt method
- * shifts the elements of the datahunkArray to close the gap created by
- * removing one element; for this reason we count down rather than up.
- */
- j = nfilestotal;
- for (n=nfilestotal-1; n >= 0; n--) {
- if ([[fileRemovalButtons cellAt:n :0] state] == 1) {
- [datahunkArray removeAt:(unsigned)n];
- j--;
- }
- }
- nfilestotal = j;
- ncurvestotal = current_index;
-
- /* Now resize and display the linestyle and symbolstyle matrices */
- [lineMatrix renewRows:N_LINE_STYLES cols:ncurvestotal];
- [lineMatrix sizeToCells];
- for (i=0; i<ncurvestotal; i++) {
- for (j=0; j<N_LINE_STYLES; j++) {
- [ [lineMatrix cellAt:j :i] setState:0];
- }
- [ [lineMatrix cellAt:newlinestyles[i] :i] setState:1];
- }
-
- [lineText renewRows:1 cols:ncurvestotal];
- [ [lineMatrix window] display];
-
- [symbolMatrix renewRows:N_SYMBOL_STYLES cols:ncurvestotal];
- [symbolMatrix sizeToCells];
- for (i=0; i<ncurvestotal; i++) {
- for (j=0; j<N_SYMBOL_STYLES; j++) {
- [ [symbolMatrix cellAt:j :i] setState:0];
- }
- [ [symbolMatrix cellAt:newsymbolstyles[i] :i] setState:1];
- }
- [symbolText renewRows:1 cols:ncurvestotal];
- [ [symbolMatrix window] display];
-
-
- /* must also fix up appearence of the file removal window */
- [self fixFileRemovalPanel:self];
- [fileRemovalPanel performClose:self];
- free((void *)newlinestyles);
- free((void *)newsymbolstyles);
-
- /* and replot automatically */
- if (nfilestotal == 0) {
- [canvas display];
- }
- else {
- [self drawPlot:self];
- }
-
- return self;
- }
-
-
- /* return the x data for the nth file */
- - (NXCoord *)xdata:(int)n
- {
- datahunk *pdh;
-
- pdh = (datahunk *)[datahunkArray elementAt:(unsigned)n];
- return pdh->x;
- }
-
- /* return the y data for the nth file */
- - (NXCoord **)ydata:(int)n
- {
- datahunk *pdh;
-
- pdh = (datahunk *)[datahunkArray elementAt:(unsigned)n];
- return pdh->y;
- }
-
- /* return the y error data for the nth file */
- - (NXCoord **)eydata:(int)n
- {
- datahunk *pdh;
-
- pdh = (datahunk *)[datahunkArray elementAt:(unsigned)n];
- return pdh->ey;
- }
-
- /* return the x error data for the nth file */
- - (NXCoord *)exdata:(int)n
- {
- datahunk *pdh;
-
- pdh = (datahunk *)[datahunkArray elementAt:(unsigned)n];
- return pdh->ex;
- }
-
- /* return the number of x-points in the nth file */
- - (int)nPoints:(int)n
- {
- datahunk *pdh;
-
- pdh = (datahunk *)[datahunkArray elementAt:(unsigned)n];
- return pdh->npoints;
- }
-
- /* return the number of curves in the nth file */
- - (int)nCurves:(int)n
- {
- datahunk *pdh;
-
- pdh = (datahunk *)[datahunkArray elementAt:(unsigned)n];
- return pdh->ncurves;
- }
-
- /* return the name of the nth file */
- - (char *)filename:(unsigned)n
- {
- datahunk *pdh;
-
- pdh = (datahunk *)[datahunkArray elementAt:n];
- return pdh->filename;
- }
-
- /* Does the nth file have error bars in y? */
- - (BOOL) has_eybars:(int)n
- {
- datahunk *pdh;
-
- pdh = (datahunk *)[datahunkArray elementAt:(unsigned)n];
- return pdh->has_eybars;
- }
-
- /* Does the nth file have error bars in x? */
- - (BOOL) has_exbars:(int)n
- {
- datahunk *pdh;
-
- pdh = (datahunk *)[datahunkArray elementAt:(unsigned)n];
- return pdh->has_exbars;
- }
-
- - (int)nCurvesTotal { return ncurvestotal;}
-
- - (int)nFiles { return nfilestotal;}
-
- - makeLineStyle:(int)aCurve :(int)lineStyle
- {
- int row;
-
- for (row = 0; row < N_LINE_STYLES; row++)
- [[lineMatrix cellAt:row :aCurve] setState:0]; /* turn off all */
- [[lineMatrix cellAt:lineStyle :aCurve] setState:1];
- return self;
- }
-
- - makeSymbolType:(int)aCurve :(int)symType;
- {
- int row;
-
- for (row = 0; row < N_SYMBOL_STYLES; row++)
- [[symbolMatrix cellAt:row :aCurve] setState:0]; /* turn off all */
- [[symbolMatrix cellAt:symType :aCurve] setState:1];
- return self;
- }
-
- - (BOOL) xaxisLog
- {
- if ( [xLinLog state] ) return YES;
- else return NO;
- }
-
- - forceXaxisLinear
- {
- [xLinLog setState:0];
- [xLinLog display];
- return self;
- }
-
- - forceXaxisLog
- {
- [xLinLog setState:1];
- [xLinLog display];
- return self;
- }
-
- - (BOOL) yaxisLog
- {
- if ( [yLinLog state] ) return YES;
- else return NO;
- }
-
- - forceYaxisLinear
- {
- [yLinLog setState:0];
- [yLinLog display];
- return self;
- }
-
- - forceYaxisLog
- {
- [yLinLog setState:1];
- [yLinLog display];
- return self;
- }
-
- - (BOOL) shouldChangeLegendFont
- {
- if ( [changeLegendFont state] ) return YES;
- else return NO;
- }
-
- - (BOOL) shouldChangeLegendTitleFont
- {
- if ( [changeLegendTitleFont state] ) return YES;
- else return NO;
- }
-
- - (BOOL) shouldChangeMainTitleFont
- {
- if ( [changeMainTitleFont state] ) return YES;
- else return NO;
- }
-
- - (BOOL) shouldChangeYTitleFont
- {
- if ( [changeYTitleFont state] ) return YES;
- else return NO;
- }
-
- - (BOOL) shouldChangeXTitleFont
- {
- if ( [changeXTitleFont state] ) return YES;
- else return NO;
- }
-
- - (BOOL) shouldChangeTicLabelFont
- {
- if ( [changeTicLabelFont state] ) return YES;
- else return NO;
- }
-
- - (int)providelinestyle:(int)aCurve
- {
- int row, cellstate;
-
- /* First, if line is turned off, return that */
- if ([ [lineMatrix cellAt:N_LINE_STYLES-1 :aCurve] state] == 1) {
- return N_LINE_STYLES-1;
- }
- /*
- * Next, check if we are printing or previewing and if we should
- * cycle the line styles
- */
- if ( ( ([printPreview state] == 1) || (NXDrawingStatus == NX_PRINTING))
- && ([accPrintLineStyleButton state] == 1) ) {
- return aCurve % (N_LINE_STYLES - 1);
- }
- /*
- * Here we can just look at the linestyle matrix.
- */
- else {
- for (row = 0; row < N_LINE_STYLES; row++) {
- cellstate = [ [lineMatrix cellAt:row :aCurve] state];
- if (cellstate == 1) return row;
- }
- }
- return 0; /* for safety */
- }
-
- - (int)providesymbolstyle:(int)aCurve
- {
- int row, cellstate;
-
- for (row = 0; row < N_SYMBOL_STYLES; row++) {
- cellstate = [ [symbolMatrix cellAt:row :aCurve] state];
- if (cellstate == 1) return row;
- }
- return 0; /* for safety */
- }
-
- /*
- * Changed floats to doubles in the following group. With floats, when
- * the value was 250.4, the value returned by floatValueAt: was
- * 250.399994 (for example). (This appears to be a problem with the
- * atof function on Unix 32-bit systems.) This gave troubles in the
- * tic mark routine in PlotView.m.
- */
- - (double)provideXmin {return [xMin doubleValueAt:0];}
- - (double)provideXmax {return [xMax doubleValueAt:0];}
- - (double)provideXinc {return [xInc doubleValueAt:0];}
- - (double)provideYmin {return [yMin doubleValueAt:0];}
- - (double)provideYmax {return [yMax doubleValueAt:0];}
- - (double)provideYinc {return [yInc doubleValueAt:0];}
-
- - resetXmin:(double)aNum { [xMin setDoubleValue:aNum at:0]; return self; }
- - resetXmax:(double)aNum { [xMax setDoubleValue:aNum at:0]; return self; }
- - resetXinc:(double)aNum { [xInc setDoubleValue:aNum at:0]; return self; }
- - resetYmin:(double)aNum { [yMin setDoubleValue:aNum at:0]; return self; }
- - resetYmax:(double)aNum { [yMax setDoubleValue:aNum at:0]; return self; }
- - resetYinc:(double)aNum { [yInc setDoubleValue:aNum at:0]; return self; }
-
- - (float)provideGlobalXmin {return globaldatamin.x;}
- - (float)provideGlobalYmin {return globaldatamin.y;}
-
- - resetMinMax:sender
- {
- int n;
- datahunk * pdh;
-
- // We have to go through all the data and recalculate min/max since
- // some data curves may have been "turned off" (by setting their linestyle
- // to none and symbolstyle to none).
-
- for (n=0; n<nfilestotal; n++) {
- pdh = (datahunk *)[datahunkArray elementAt:(unsigned)n];
- [self findMinMax:pdh];
- }
- [self findGlobalMinMax];
-
- [self niceMinMaxInc];
- [self drawPlot:self]; /* redraw plot automatically */
- return self;
- }
-
- - drawPlotButton:(int)state
- {
- if (state==0) {
- [plotButton highlight:NO]; /* will display normal title */
- }
- if (state==1) {
- [plotButton highlight:YES]; /* will display alternate title */
- }
- return self;
- }
-
- // We make the plotParam object responsible for checking parameters
- // before the PlotView object is called. Thus the PlotView object can
- // assume the parameters are OK, and it doesn't have to do any checking.
- // Things to check: xinc has the same sign as xmax-xmin (same for y);
- // no negative data if log plot requested on x or y axis; there won't be
- // too many tic marks requested.
- - sanityCheck
- {
- float xinc = [self provideXinc];
- float xmax = [self provideXmax], xmin = [self provideXmin];
- float yinc = [self provideYinc];
- float ymax = [self provideYmax], ymin = [self provideYmin];
- int nticmarks;
-
- /* First check: no nonpositive data if logarithmic axis */
- /* Also check that increment is > 5 (need rint(log10(increment)) >=1 ) */
- if ( [self xaxisLog] ) {
- if (globaldatamin.x <= 0.0 || xmin <= 0.0 || xmax <= 0.0) {
- [xLinLog setState:0]; /* back to linear */
- NXBeep(); /* audible alert */
- beepError = 1;
- }
- if (xinc < 5.0) {
- [self resetXinc:(double)10.0];
- NXBeep();
- beepError = 12;
- }
- }
- if ( [self yaxisLog] ) {
- if (globaldatamin.y <= 0.0 || ymin <= 0.0 || ymax <= 0.0) {
- [yLinLog setState:0]; /* back to linear */
- NXBeep(); /* audible alert */
- beepError = 2;
- }
- if (yinc < 5.0) {
- [self resetYinc:(double)10.0];
- NXBeep();
- beepError = 12;
- }
- }
- /* Second check: xinc has same sign as xmax and xmin */
- if (xinc*(xmax-xmin) <= 0.0) { /* the bad case - avoid infinite loop */
- if (xinc < 0.0) { /* in PlotView:drawSelf */
- xinc = -xinc;
- [self resetXinc:xinc];
- NXBeep();
- beepError = 3;
- }
- if (xmax <= xmin) {
- [self niceMinMaxInc];
- NXBeep(); /* alert */
- beepError = 4;
- }
- }
- /* And similarly for yinc */
- if (yinc*(ymax-ymin) <= 0.0) { /* the bad case - avoid infinite loop */
- if (yinc < 0.0) {
- yinc = -yinc;
- [self resetYinc:yinc];
- NXBeep(); /* alert */
- beepError = 5;
- }
- if (ymax <= ymin) {
- [self niceMinMaxInc];
- NXBeep(); /* alert */
- beepError = 6;
- }
- }
- /* Third check: no more than 100 (say) tic marks on either axis */
- if ( ![self xaxisLog] ) { /* linear axis */
- nticmarks = (int) ((xmax - xmin) / xinc) ;
- if (nticmarks > 100) {
- computeNiceLinInc(&xmin, &xmax, &xinc);
- [self resetXmin:xmin];
- [self resetXmax:xmax];
- [self resetXinc:xinc];
- NXBeep(); /* alert */
- beepError = 7;
- }
- }
- if ( ![self yaxisLog] ) { /* linear axis */
- nticmarks = (int) ((ymax - ymin) / yinc) ;
- if (nticmarks > 100) {
- computeNiceLinInc(&ymin, &ymax, &yinc);
- [self resetYmin:ymin];
- [self resetYmax:ymax];
- [self resetYinc:yinc];
- NXBeep(); /* alert */
- beepError = 8;
- }
- }
-
- return self;
- }
-
- - drawPlot:sender
- {
- char c_xmin[20], c_xmax[20], c_ymin[20], c_ymax[20], c_xinc[20], c_yinc[20];
- float xmin, xmax, ymin, ymax, xinc, yinc;
-
- if (nfilestotal==0) return self;
-
- [self drawPlotButton:1]; /* display "Plotting" */
- [self sanityCheck]; /* disallow various bad parameters */
-
- /* maybe save min/max/inc */
- /* This really gets crufty: when we look at the TextField xMin and
- * get its float value via [xMin floatValueAt:0], we get
- * a float which is the result of applying atof() to a string. The
- * float which results may not be the same as the float that was originally
- * written into the TextField. So we apply the process ourselves:
- * float --> string (via sprintf) --> float (via atof). Ugly, but necessary
- * (otherwise, if you zoom, then hit the Plot button twice, then hit
- * the Previous View button, you might not get back to where you want).
- */
- sprintf(c_xmin,"%f",currentMin.x);
- sprintf(c_xmax,"%f",currentMax.x);
- sprintf(c_xinc,"%f",currentInc.x);
- sprintf(c_ymin,"%f",currentMin.y);
- sprintf(c_ymax,"%f",currentMax.y);
- sprintf(c_yinc,"%f",currentInc.y);
- xmin = (float)atof(c_xmin);
- xmax = (float)atof(c_xmax);
- xinc = (float)atof(c_xinc);
- ymin = (float)atof(c_ymin);
- ymax = (float)atof(c_ymax);
- yinc = (float)atof(c_yinc);
- if ( [xMin floatValueAt:0] != xmin
- || [xMax floatValueAt:0] != xmax
- || [xInc floatValueAt:0] != xinc
- || [yMin floatValueAt:0] != ymin
- || [yMax floatValueAt:0] != ymax
- || [yInc floatValueAt:0] != yinc ) {
- oldMin.x = currentMin.x;
- currentMin.x = [xMin floatValueAt:0];
- oldMax.x = currentMax.x;
- currentMax.x = [xMax floatValueAt:0];
- oldInc.x = currentInc.x;
- currentInc.x = [xInc floatValueAt:0];
- oldMin.y = currentMin.y;
- currentMin.y = [yMin floatValueAt:0];
- oldMax.y = currentMax.y;
- currentMax.y = [yMax floatValueAt:0];
- oldInc.y = currentInc.y;
- currentInc.y = [yInc floatValueAt:0];
- }
-
- [canvas display];
- [self drawPlotButton:0]; /* display "Plot" */
- return self;
- }
-
- // Allocate enough memory and read the data points
- /*
- * This code makes the following assumptions:
- * 1. Any data on a line following the character "!" is to be discarded.
- * 2. We can determine the number of curves by looking at the first
- * line of data, which should be of the form
- * x y1 y2 ... yn
- * (possibly separated by commas, with possible trailing comment).
- * 3. Other lines of the file may contain arbitrary text, but contain no
- * numerals or periods (these get interpreted as floating point numbers
- * when the file is scanned); also, anything after a "!" is discarded.
- *
- * It is not easy to make a completely general and bullet-proof scanning
- * routine. This code is fairly robust and was easy to write.
- */
- - (int) readData:(NXStream *)aDataStream :(char *)fname
- {
- BOOL inword = NO;
- char c;
- int j, size = ALLOCSIZE;
- int tmpint = 0; /* tmpint initialized to avoid compiler warning */
- int oldncurves = ncurvestotal;
- datahunk *pdh = (void *)NULL;
- BOOL noxdata = NO;
- float tmpfloat = 0.0; /* initialized to avoid compiler warning */
-
- [self preludeToReading:fname :&pdh]; /* take care of some housekeeping */
-
- /* Figure out the number of curves in the file by reading characters */
- /* until a newline is encountered; the number of curves is one less */
- /* than the number of words found. */
- /* We assume the input file is an ascii file; a compressed file will */
- /* have been pumped through zcat and written to a temporary file. */
- pdh->ncurves = -1;
- top_of_file: ;
- while (1) {
- c = (char)NXGetc(aDataStream);
- if (c == '\n' || c == (char)EOF) {
- break; /* breaks out of while loop */
- }
- if (c == '!') { /* comment signal: start discarding characters */
- while ( (c=(char)NXGetc(aDataStream)) != '\n' ) ; /* do nothing */
- if (pdh->ncurves == -1) /* any data found yet? */
- goto top_of_file; /* ugh */
- else
- break;
- }
- else if ((inword==NO) && !(c==' ' || c=='\t')) {
- pdh->ncurves++;
- inword = YES;
- }
- else if ((inword==YES) && (c==' ' || c=='\t')) {
- inword = NO;
- }
- }
- if (pdh->ncurves == -1) { /* couldn't find "\n", give up (after cleanup) */
- [plotButton setAltTitle:"Plotting"]; /* reset plot button */
- [plotButton highlight:NO];
- NXPing(); /* force redraw */
- free( (void *)(pdh->filename) );
- nfilestotal--;
- return 0;
- }
- if (pdh->ncurves == 0) { /* only one column, assume x data are integers */
- noxdata = YES;
- tmpfloat = 1.0;
- pdh->ncurves = 1;
- if (pdh->has_exbars || pdh->has_eybars) {
- NXRunAlertPanel("Read Data (with error bars)",
- "Error bars expected, only one curve found\n"
- "Unsetting error bar button and continuing",
- "OK", NULL, NULL);
- [errorBars setTitle:"No error bars"];
- pdh->has_exbars = NO;
- pdh->has_eybars = NO;
- }
- }
-
- /*
- * We read more than one column; if there are error bars we must adjust ncurves.
- * case pdh->ncurves true no. of curves
- * y only 2n n
- * x only n (>=2) n-1
- * y and x 2n+1 (>=3) n
- */
- if (pdh->has_eybars && !pdh->has_exbars) {
- if ( pdh->ncurves % 2 != 0 ) {
- NXRunAlertPanel("Read Data (with error bars)",
- "Strange number of curves found\n"
- "Unsetting error bar button and continuing",
- "OK", NULL, NULL);
- [errorBars setTitle:"No error bars"];
- pdh->has_eybars = NO;
- }
- else {
- pdh->ncurves = pdh->ncurves / 2;
- }
- }
- else if (pdh->has_exbars && !pdh->has_eybars) {
- if ( pdh->ncurves < 2 ) {
- NXRunAlertPanel("Read Data (with error bars)",
- "Too few curves found\n"
- "Unsetting error bar button and continuing",
- "OK", NULL, NULL);
- [errorBars setTitle:"No error bars"];
- pdh->has_exbars = NO;
- }
- else {
- pdh->ncurves--;
- }
- }
- else if (pdh->has_exbars && pdh->has_eybars) {
- if ( pdh->ncurves < 3 || pdh->ncurves % 2 == 0 ) {
- NXRunAlertPanel("Read Data (with error bars)",
- "Bad number of curves found\n"
- "Unsetting error bar button and continuing",
- "OK", NULL, NULL);
- [errorBars setTitle:"No error bars"];
- pdh->has_exbars = NO;
- pdh->has_eybars = NO;
- }
- else {
- pdh->ncurves = (pdh->ncurves - 1) / 2;
- }
- }
-
- /* Now read the data into memory */
- NXSeek(aDataStream, 0L, NX_FROMSTART);
-
- pdh->x = (NXCoord *)malloc( size * sizeof(NXCoord) );
- if (pdh->has_exbars) {
- pdh->ex = (NXCoord *)malloc( size * sizeof(NXCoord) );
- }
- pdh->y = (NXCoord **)malloc( pdh->ncurves * sizeof(NXCoord *) );
- for (j = 0; j < pdh->ncurves; j++) {
- *(pdh->y+j) = (NXCoord *)malloc( size * sizeof(NXCoord) );
- }
- if (pdh->has_eybars) {
- pdh->ey = (NXCoord **)malloc( pdh->ncurves * sizeof(NXCoord *) );
- for (j = 0; j < pdh->ncurves; j++) {
- *(pdh->ey+j) = (NXCoord *)malloc( size * sizeof(NXCoord) );
- }
- }
- pdh->npoints = 0;
- while(1) {
- if (noxdata) {
- *(pdh->x+pdh->npoints) = tmpfloat++;
- }
- else {
- if (pdh->has_exbars) { /* x error bars, read two items*/
- while ( (tmpint=NXScanf(aDataStream, "%f", pdh->x+pdh->npoints)) == 0 ) {
- if (c == '!') {
- while ( (c=(char)NXGetc(aDataStream)) != '\n' ) ; /* do nothing */
- goto skipline; /* ugh */
- }
- }
- while ( (tmpint=NXScanf(aDataStream, "%f", pdh->ex+pdh->npoints)) == 0 ) {
- if (c == '!') {
- while ( (c=(char)NXGetc(aDataStream)) != '\n' ) ; /* do nothing */
- goto skipline; /* ugh */
- }
- }
- }
- else { /* no x error bars, read one item */
- while ( (tmpint=NXScanf(aDataStream, "%f", pdh->x+pdh->npoints)) == 0 ) {
- c = (char)NXGetc(aDataStream); /* throw away extraneous characters */
- if (c == '!') {
- while ( (c=(char)NXGetc(aDataStream)) != '\n' ) ; /* do nothing */
- goto skipline; /* ugh */
- }
- }
- }
- if (tmpint == EOF) break; /* break out of the while(1) loop */
- }
-
- if (pdh->has_eybars) { /* y error bars, read two items */
- for (j = 0; j < 2 * pdh->ncurves; j++) {
- if (j%2 == 0) { /* j is even, reading y value */
- while( (tmpint=NXScanf(aDataStream, "%f", *(pdh->y+(j/2))+ pdh->npoints)) == 0 ) {
- c = (char)NXGetc(aDataStream); /* throw away the next character */
- if (c == '!') { /* comment signal; start discarding characters */
- while ( (c=(char)NXGetc(aDataStream)) != '\n' ) ; /* do nothing */
- goto skipline; /* ugh */
- }
- }
- }
- else { /* j is odd, reading error */
- while( (tmpint=NXScanf(aDataStream, "%f", *(pdh->ey+(j-1)/2)+ pdh->npoints)) == 0 ) {
- c = (char)NXGetc(aDataStream);
- if (c == '!') {
- while ( (c=(char)NXGetc(aDataStream)) != '\n' ) ;
- goto skipline;
- }
- }
- }
- }
- }
- else { /* no error bars, read one item */
- for (j = 0; j < pdh->ncurves; j++) {
- /*
- * Try to allow extraneous characters here (if scanf returns 0, which means
- * it didn't find a number, just do a getc on the input stream to throw that
- * character away. This will allow commas and alphabetic characters in the
- * middle of an input line (no digits or periods, though!).
- */
- while( (tmpint=NXScanf(aDataStream, "%f", *(pdh->y+j)+ pdh->npoints)) == 0 ) {
- c = (char)NXGetc(aDataStream); /* throw away the next character */
- if (c == '!') { /* comment signal; start discarding characters */
- while ( (c=(char)NXGetc(aDataStream)) != '\n' ) ; /* do nothing */
- goto skipline; /* ugh */
- }
- }
- }
- }
- if (tmpint == EOF) break; /* could get this if noxdata==YES */
- pdh->npoints++;
- if (pdh->npoints == size) { /* get more memory */
- size += ALLOCSIZE;
- pdh->x = (NXCoord *)realloc(pdh->x, size * sizeof(NXCoord));
- if (pdh->has_exbars) {
- pdh->ex = (NXCoord *) realloc(pdh->ex, size * sizeof(NXCoord));
- }
- for (j = 0; j < pdh->ncurves; j++) {
- *(pdh->y+j) = (NXCoord *)realloc( *(pdh->y+j), size * sizeof(NXCoord) );
- }
- if (pdh->has_eybars) {
- for (j = 0; j < pdh->ncurves; j++) {
- *(pdh->ey+j) = (NXCoord *)realloc( *(pdh->ey+j), size * sizeof(NXCoord) );
- }
- }
- }
- skipline: ;
- }
-
- [self postludeToReading:fname :oldncurves :pdh];
-
- ncurvestotal += pdh->ncurves;
-
- return pdh->npoints;
- }
-
- /* Might want to make sure INLINE_MATH is defined when math.h is included
- * (for guaranteed fast logarithms?)
- */
- - checkLinLog:(datahunk *)pdh
- {
- /* Check x and y axes -- do a heuristic test for log/lin.
- * The test employed comes from M. Merriam and xyplot.
- */
- double scale, linsum, logsum;
- register double tmp;
- int i, j;
-
- /* First test x axis. */
- if (pdh->datamax.x > 0.0 && pdh->datamin.x > 0.0
- && pdh->datamax.x != pdh->datamin.x) {
- scale = fabs( (double)pdh->datamax.x - (double)pdh->datamin.x );
- linsum = 0.0;
- for (j=1; j<pdh->npoints; j++) {
- tmp = ( (double)pdh->x[j]-(double)pdh->x[j-1] )/(double)scale;
- linsum += tmp*tmp;
- }
- scale = log10( (double)pdh->datamax.x/(double)pdh->datamin.x );
- /* what if datamax.x<datamin.x? */
- logsum = 0.0;
- for (i=1; i<pdh->npoints; i++) {
- tmp = log10( (double)pdh->x[i]/(double)pdh->x[i-1] ) / scale;
- logsum += tmp*tmp;
- }
- if (linsum < logsum) {
- pdh->xaxislin = YES; /* linear axis */
- }
- else {
- pdh->xaxislin = NO; /* logarithmic axis */
- }
- }
- else {
- pdh->xaxislin = YES; /* linear */
- }
- /* Now test y axis */
- if (pdh->datamax.y > 0.0 && pdh->datamin.y > 0.0
- && pdh->datamax.y != pdh->datamin.y) {
- scale = fabs( (double)pdh->datamax.y - (double)pdh->datamin.y );
- linsum = 0.0;
- for (j=0; j<pdh->ncurves; j++) {
- for (i=1; i<pdh->npoints; i++) {
- tmp = ( (double)*(*(pdh->y+j)+i) - (double)*(*(pdh->y+j)+i-1) )
- / scale; /* avoid overflow */
- linsum += tmp*tmp;
- }
- }
- scale = log10((double)pdh->datamax.y/(double)pdh->datamin.y);
- logsum = 0.0;
- for (j=0; j<pdh->ncurves; j++) {
- for (i=1; i<pdh->npoints;i++) {
- tmp = log10( (double)*(*(pdh->y+j)+i)/(double)*(*(pdh->y+j)+i-1) ) / scale;
- logsum += tmp*tmp;
- }
- }
- if (linsum < logsum) {
- pdh->yaxislin = YES; /* linear axis */
- }
- else {
- pdh->yaxislin = NO; /* logarithmic axis */
- }
- }
- else {
- pdh->yaxislin = YES; /* linear */
- }
- return self;
- }
-
- // This routine works as follows:
- // If these is just one file, we set the x and y axes to linear or logarithmic
- // depending on our heuristic.
- // If there is more than one file, we don't change the axes unless there
- // would be an illegal result (trying to plot a negative number on a
- // logarithmic axis).
- - checkGlobalLinLog
- {
- datahunk *pdh;
-
- if (nfilestotal == 1) {
- pdh = (datahunk *)[datahunkArray elementAt:0];
- if ( pdh->xaxislin )
- [xLinLog setState:0]; /* linear */
- else
- [xLinLog setState:1]; /* logarithmic */
- if ( pdh->yaxislin )
- [yLinLog setState:0]; /* linear */
- else
- [yLinLog setState:1]; /* logarithmic */
- }
- else {
- if ( [self xaxisLog] && globaldatamin.x <= 0.0) {
- [xLinLog setState:0]; /* back to linear */
- NXBeep(); /* audible alert */
- beepError = 9;
- }
- if ( [self yaxisLog] && globaldatamin.y <= 0.0) {
- [yLinLog setState:0]; /* back to linear */
- NXBeep(); /* audible alert */
- beepError = 10;
- }
- }
- [xLinLog display];
- [yLinLog display];
-
- return self;
- }
-
- - adjustLineStyleMatrix:(int)column :(int)row
- {
- /* Adjust the given column of the lineMatrix object, turning off all
- * buttons except for the given row.
- */
- int i;
-
- for (i = 0; i < N_LINE_STYLES; i++) {
- [ [lineMatrix cellAt:i :column] setState:0];
- }
- [ [lineMatrix cellAt:row :column] setState:1];
-
- return self;
- }
-
- - redisplayLineStyleMatrix
- {
- [lineMatrix display];
- return self;
- }
-
- - adjustSymbolTypeMatrix:(int)column :(int)row
- {
- /* Adjust the given column of the symbolMatrix object, turning off all
- * buttons except for the given row.
- */
- int i;
-
- for (i = 0; i < N_SYMBOL_STYLES; i++) {
- [ [symbolMatrix cellAt:i :column] setState:0];
- }
- [ [symbolMatrix cellAt:row :column] setState:1];
- return self;
- }
-
- - redisplaySymbolTypeMatrix
- {
- [symbolMatrix display];
- return self;
- }
-
- - adjustPanels:(int)oldn :(int)newn
- {
- /*
- * Resize the linestyle matrix, the symbolstyle matrix, and
- * the legend form.
- * Also arrange to select and highlight only the top button in
- * each column of the linestyle and symbolstyle matrices.
- * This code could stand to be cleaned up.
- */
- char formtitle[80];
- int j, k;
- // some additions on by pdhowell for ScrollWindow compatibility
- NXRect legendFormFrame, lineMatrixFrame, symbolMatrixFrame;
- datahunk *pdh;
-
- if (newn == -1) { /* flag to delete all and start over */
- for (j=oldn-1; j>=1; j--) {
- [lineText removeColAt:j andFree:YES];
- [symbolText removeColAt:j andFree:YES];
- [lineMatrix removeColAt:j andFree:YES];
- [symbolMatrix removeColAt:j andFree:YES];
- [legendForm removeEntryAt:j];
- }
- for (j=0; j<1; j++) {
- if ( [ [lineMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */
- [ [lineMatrix cellAt:0 :j] setState:1];
- if ( [ [symbolMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */
- [ [symbolMatrix cellAt:0 :j] setState:1];
- for (k=1; k<N_LINE_STYLES; k++) {
- [ [lineMatrix cellAt:k :j] setState:0];
- }
- for (k=1; k<N_SYMBOL_STYLES; k++) {
- [ [symbolMatrix cellAt:k :j] setState:0];
- }
- sprintf(formtitle, "Curve %d", j+1);
- [legendForm setStringValue:formtitle at:j];
- [legendForm drawCellAt:j];
- sprintf(formtitle, "%d", j+1);
- [[lineText cellAt:0 :j] setStringValue:formtitle]; /* titles on columns */
- [[symbolText cellAt:0 :j] setStringValue:formtitle]; /* titles on columns */
- }
- // [legendTitle setStringValue:"Legend" at:0]; should we uncomment this?
- // (would need to add an outlet in IB)
- [lineText sizeToCells];
- [symbolText sizeToCells];
- [lineMatrix sizeToCells];
- [symbolMatrix sizeToCells];
- [legendForm sizeToFit];
- [ [lineMatrix window] display]; /* redraw the whole window so extra */
- [ [symbolMatrix window] display]; /* columns get erased */
- [ [legendForm window] display];
- [curveNumber setIntValue:1]; /* update curve no. on color panel */
- [curveColorWell setColor:NX_COLORBLACK]; /* and update the color */
- /* (the background and text color wells are not reset) */
- }
-
- if ( (oldn == 0) && (newn > 1) ) { /* can only happen first time */
- pdh = [datahunkArray elementAt:0];
- for (j=1; j<newn; j++) {
- [lineText addCol];
- [symbolText addCol];
- [lineMatrix addCol];
- if ( [ [lineMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */
- [ [lineMatrix cellAt:0 :j] setState:1];
- /* highlight 1st row new column -- this occurs automatically */
- [symbolMatrix addCol];
- if ( [ [symbolMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */
- [ [symbolMatrix cellAt:0 :j] setState:1];
- /* highlighting of 1st row new column occurs automatically */
- sprintf(formtitle, "Curve %d:", j+1);
- [legendForm addEntry:formtitle];
- sprintf(formtitle, "%s, Curve %d",
- strrchr(pdh->filename,'/')==NULL ? pdh->filename
- : strrchr(pdh->filename,'/') + 1,
- j+1);
- [legendForm setStringValue:formtitle at:j];
- [legendForm drawCellAt:j];
- sprintf(formtitle, "%d", j+1);
- [[lineText cellAt:0 :j] setStringValue:formtitle]; /* titles on columns */
- [[symbolText cellAt:0 :j] setStringValue:formtitle]; /* titles on columns */
- }
- sprintf(formtitle, "%s, Curve 1",
- strrchr(pdh->filename,'/')==NULL ? pdh->filename
- : strrchr(pdh->filename,'/') + 1);
- [legendForm setStringValue:formtitle at:0];
- [legendForm drawCellAt:0];
- [lineText sizeToCells];
- [symbolText sizeToCells];
- [lineMatrix sizeToCells];
- [symbolMatrix sizeToCells];
- [legendForm sizeToFit];
- [lineText display];
- [symbolText display];
- [lineMatrix display]; /* don't need to redraw the window here */
- [symbolMatrix display];
- [legendForm display];
- }
- if ( (oldn == 0) && (newn == 1) ) { /* only for legendForm update */
- pdh = [datahunkArray elementAt:0];
- sprintf(formtitle, "%s, Curve 1",
- strrchr(pdh->filename,'/')==NULL ? pdh->filename
- : strrchr(pdh->filename,'/') + 1);
- [legendForm setStringValue:formtitle at:0];
- [legendForm drawCellAt:0];
- [legendForm display];
- }
- if ( oldn != 0 ) { /* must add columns */
- pdh = [datahunkArray elementAt:(nfilestotal-1)];
- for (j=oldn; j<oldn+newn; j++) {
- [lineText addCol];
- [symbolText addCol];
- [lineMatrix addCol];
- [ [lineMatrix cellAt:0 :j] setState:1];
- /* highlighting of 1st row new column occurs automatically */
- [symbolMatrix addCol];
- [ [symbolMatrix cellAt:0 :j] setState:1];
- /* highlighting of 1st row new column occurs automatically */
- sprintf(formtitle, "Curve %d:", j+1);
- [legendForm addEntry:formtitle];
- sprintf(formtitle, "%s, Curve %d",
- strrchr(pdh->filename,'/')==NULL ? pdh->filename
- : strrchr(pdh->filename,'/') + 1,
- j+1-oldn);
- [legendForm setStringValue:formtitle at:j];
- [legendForm drawCellAt:j];
- sprintf(formtitle, "%d", j+1);
- [[lineText cellAt:0 :j] setStringValue:formtitle];
- [[symbolText cellAt:0 :j] setStringValue:formtitle];
- }
- [lineText sizeToCells];
- [symbolText sizeToCells];
- [lineMatrix sizeToCells];
- [symbolMatrix sizeToCells];
- [legendForm sizeToFit];
- [lineText display];
- [symbolText display];
- [lineMatrix display]; /* don't need to redraw the window here */
- [symbolMatrix display];
- [legendForm display];
- }
-
- // added code here by pdhowell for ScrollWindowing
- [legendForm getFrame:&legendFormFrame];
- [lineMatrix getFrame:&lineMatrixFrame];
- [symbolMatrix getFrame:&symbolMatrixFrame];
- // Put MAX in the the following lines because we don't want to allow the windows
- // to get so small that the sliders aren't drawn; the 282 and 288 are the original
- // sizes of the lineMatrixWindow and symbolMatrixWindow -- dcj
- [[[lineMatrixWindow contentView] docView]
- sizeTo:MAX(128.0+lineMatrixFrame.size.width,282.0)
- :92+lineMatrixFrame.size.height];
- [[[symbolMatrixWindow contentView] docView]
- sizeTo:MAX(128.0+symbolMatrixFrame.size.width,288.0)
- :92+symbolMatrixFrame.size.height];
- [[[legendFormWindow contentView] docView]
- sizeTo:32+legendFormFrame.size.width
- :192+legendFormFrame.size.height];
-
- // Try sending windowDidResize (the "self" is bogus but does no harm) -- dcj
- [legendFormWindow windowDidResize:self];
- [lineMatrixWindow windowDidResize:self];
- [symbolMatrixWindow windowDidResize:self];
-
- // Try to get the windows to display properly ... dcj
- [ [lineMatrix window] display];
- [ [symbolMatrix window] display];
- [ [legendForm window] display];
-
- return self;
- }
-
- // Go through a particular datahunk and find values for datamin.x,
- // datamax.x, datamin.y, datamax.y
- // We ignore any curves that are "turned off" (linestyle=NONE & symbolstyle=NONE);
- // if all curves in the datahunk are turned off we ignore the x-data, too.
- - findMinMax:(datahunk *)pdh
- {
- int i, j;
- datahunk *qdh;
- int n, ncurve;
- BOOL ignore;
-
- pdh->datamin.x = MAXFLOAT;
- pdh->datamax.x = -MAXFLOAT;
- pdh->datamin.y = MAXFLOAT;
- pdh->datamax.y = -MAXFLOAT;
-
- // Find out which curves belong to datahunk pdh
- ncurve = 0;
- for (n=0; n<nfilestotal; n++) {
- qdh = (datahunk *)[datahunkArray elementAt:(unsigned)n];
- if (qdh == pdh)
- break;
- else
- ncurve += qdh->ncurves;
- }
- // Now we know to look at curves ncurve, ncurve+1,...,ncurve+pdh->ncurves-1
- ignore = YES;
- for (n = ncurve; n < ncurve + pdh->ncurves; n++) {
- if ([self providelinestyle:n] != NOLINE
- || [self providesymbolstyle:n] != NOSYMBOL)
- ignore = NO;
- }
- // Now it's possible we want to ignore all the curves.
- if (ignore) return self;
-
- // If we don't ignore all the curves then we must look at the x data.
- for (i = 0; i < pdh->npoints; i++) {
- pdh->datamin.x = MIN(pdh->datamin.x, pdh->x[i]);
- pdh->datamax.x = MAX(pdh->datamax.x, pdh->x[i]);
- }
- for (j = 0; j < pdh->ncurves; j++) {
- if ([self providelinestyle:(ncurve+j)] != NOLINE
- || [self providesymbolstyle:(ncurve+j)] != NOSYMBOL) {
- for (i = 0; i < pdh->npoints; i++) {
- pdh->datamin.y = MIN(pdh->datamin.y, *(*(pdh->y+j)+i));
- pdh->datamax.y = MAX(pdh->datamax.y, *(*(pdh->y+j)+i));
- }
- }
- }
- return self;
- }
-
- - findGlobalMinMax
- {
- int n;
- datahunk *pdh;
-
- globaldatamin.x = MAXFLOAT;
- globaldatamin.y = MAXFLOAT;
- globaldatamax.x = -MAXFLOAT;
- globaldatamax.y = -MAXFLOAT;
- for (n=0; n<nfilestotal; n++) {
- pdh = (datahunk *)[datahunkArray elementAt:(unsigned)n];
- globaldatamin.x = MIN(globaldatamin.x, pdh->datamin.x);
- globaldatamax.x = MAX(globaldatamax.x, pdh->datamax.x);
- globaldatamin.y = MIN(globaldatamin.y, pdh->datamin.y);
- globaldatamax.y = MAX(globaldatamax.y, pdh->datamax.y);
- }
- return self;
- }
-
- // Get pleasing values for the min, max, and increments
- - niceMinMaxInc
- {
- float fmin, fmax, finc;
-
- fmin = globaldatamin.x;
- fmax = globaldatamax.x;
- if ([self xaxisLog] ) {
- computeNiceLogInc(&fmin, &fmax, &finc);
- }
- else {
- computeNiceLinInc(&fmin, &fmax, &finc);
- }
- [self resetXmin:fmin];
- [self resetXmax:fmax];
- [self resetXinc:finc];
-
- fmin = globaldatamin.y;
- fmax = globaldatamax.y;
- if ([self yaxisLog] ) {
- computeNiceLogInc(&fmin, &fmax, &finc);
- }
- else {
- computeNiceLinInc(&fmin, &fmax, &finc);
- }
- [self resetYmin:fmin];
- [self resetYmax:fmax];
- [self resetYinc:finc];
- return self;
- }
-
- // Use the OpenPanel object to get a filename
- - open:sender
- {
- static const char *const fileTypes[2] = {NULL, NULL};
- /* this is supposedly all ASCII files */
- char fname[256];
- char tempfname[256], command[512];
- id openPanel = [[OpenPanel new] allowMultipleFiles:NO];
-
- [openPanel setAccessoryView:nil]; /* may have to clean out an accessory view */
- if (nfilestotal == 0) {
- if (strncmp([errorBars title], "No error bars", 13) != 0) {
- [openPanel setTitle:"Open (error bars)"];
- }
- else {
- [openPanel setTitle:"Open"]; /* make sure title is OK (cf. binary open) */
- }
- }
- else {
- if (strncmp([errorBars title], "No error bars", 13) != 0) {
- [openPanel setTitle:"Another (error bars)"]; /* 21 character limit here? */
- }
- else {
- [openPanel setTitle:"Open Additional File"];
- }
- }
-
- if ([openPanel runModalForTypes:fileTypes]) {
- strncpy(fname, (char *)[openPanel filename], 256);
- // Check to see if we are trying to open a compressed file:
- if (fname[strlen(fname)-1]=='Z' && fname[strlen(fname)-2]=='.') {
- // set plot button title:
- [plotButton setAltTitle:"Uncompressing"];
- [plotButton highlight:YES];
- NXPing(); /* force plotButton redraw */
- // Uncompress the file into a temporary file:
- strcpy(tempfname, "/tmp/file000000.xyp");
- NXGetTempFilename(tempfname, 9);
- sprintf(command, "zcat %s > %s\n", fname, tempfname);
- system(command); /* no error checking */
- // Now just go ahead and open the temporary file:
- [self openFile:tempfname :fname];
- // After returning from the openFile it is safe to unlink:
- unlink(tempfname);
- }
- else {
- [self openFile:fname :fname];
- }
- }
- return self;
- }
-
- - openFile:(char *)dataFile :(char *)realName
- {
- NXStream *dataStream;
-
- if ((dataStream = NXMapFile(dataFile, NX_READONLY)) == NULL) {
- NXRunAlertPanel("Open", "Cannot open %s", "OK", NULL, NULL, dataFile);
- return self;
- }
-
- if ([self readData:dataStream :realName] == 0) {
- NXRunAlertPanel("Read", "Couldn't read any data from %s", "OK",
- NULL, NULL, dataFile);
- NXCloseMemory(dataStream, NX_FREEBUFFER);
- return self;
- }
- NXCloseMemory(dataStream, NX_FREEBUFFER);
- [self plotPrepAndDraw];
- return self;
- }
-
- - openBinary:sender
- {
- static const char *const fileTypes[2] = {NULL, NULL};
- char fname[256];
- id openPanel = [[OpenPanel new] allowMultipleFiles:NO];
-
- [openPanel setAccessoryView:binaryOpenAccessory];
- if (strncmp([errorBars title], "No error bars", 13) != 0) {
- [openPanel setTitle:"Open Binary (error bars)"];
- }
- else {
- [openPanel setTitle:"Open Binary File"];
- }
-
- if ([openPanel runModalForTypes:fileTypes]) {
- if ([binaryOpenForm intValueAt:0] < 1) {
- NXRunAlertPanel("Binary Read",
- "Number of curves is less than 1\n"
- "Be sure to set this correctly",
- "OK", NULL, NULL);
- return self;
- }
- strncpy(fname, (char *)[openPanel filename], 256);
- [self openBinaryFile:fname];
- }
- return self;
- }
-
- #import <sys/stat.h>
- - openBinaryFile:(char *)dataFile
- {
- struct stat filestat;
- int filesize, numpoints;
- int numcurves = [binaryOpenForm intValueAt:0];
- BOOL xdatathere = [binaryXdatathere state];
- NXStream *dataStream;
- int numcols; /* number of "columns" expected in the data file */
-
- if (strncmp([errorBars title], "No error bars", 13) == 0) {
- numcols = numcurves; /* no error bars */
- }
- else if (strncmp([errorBars title], "y only", 6) == 0) {
- numcols = 2*numcurves;
- }
- else if (strncmp([errorBars title], "x only", 6) == 0) {
- numcols = numcurves + 1;
- }
- else {
- numcols = 2*numcurves + 1;
- }
-
- stat(dataFile, &filestat);
- filesize = filestat.st_size;
-
- if (xdatathere) {
- // This consistency check is not sufficient to guarantee numcurves is
- // correct, but it's better than nothing.
- if ( (filesize % (sizeof(NXCoord)*(numcols+1))) != 0 ) {
- NXRunAlertPanel("Binary Read",
- "File size inconsistent with number\n"
- "of curves specified",
- "OK", NULL, NULL);
- return self;
- }
- numpoints = filesize/(sizeof(NXCoord)*(numcols+1));
- }
- else {
- if ( (filesize % (sizeof(NXCoord)*numcols)) != 0 ) {
- NXRunAlertPanel("Binary Read",
- "File size inconsistent with number\n"
- "of curves specified",
- "OK", NULL, NULL);
- return self;
- }
- numpoints = filesize/(sizeof(NXCoord)*(numcols));
- }
-
- if ((dataStream = NXMapFile(dataFile, NX_READONLY)) == NULL) {
- NXRunAlertPanel("Open", "Cannot open %s", "OK", NULL, NULL, dataFile);
- return self;
- }
-
- if ([self readBinaryData:dataStream :dataFile :numcurves
- :numpoints :xdatathere] == 0) {
- NXRunAlertPanel("Read", "Couldn't read any data from %s", "OK",
- NULL, NULL, dataFile);
- NXCloseMemory(dataStream, NX_FREEBUFFER);
- return self;
- }
- NXCloseMemory(dataStream, NX_FREEBUFFER);
- [self plotPrepAndDraw];
-
- return self;
- }
-
- - (int)readBinaryData:(NXStream *)aDataStream
- :(char *)fname
- :(int)numcurves
- :(int)numpoints
- :(BOOL)xdatathere
- {
- int j, oldncurves = ncurvestotal;
- datahunk *pdh = (void *)NULL;
-
- [self preludeToReading:fname :&pdh]; /* take care of some housekeeping */
- pdh->ncurves = numcurves;
-
- /* Now read the data into memory */
- NXSeek(aDataStream, 0L, NX_FROMSTART);
-
- pdh->x = (NXCoord *)malloc( numpoints * sizeof(NXCoord) );
- if (pdh->has_exbars) {
- pdh->ex = (NXCoord *)malloc( numpoints * sizeof(NXCoord *) );
- }
- pdh->y = (NXCoord **)malloc( pdh->ncurves * sizeof(NXCoord *) );
- for (j = 0; j < pdh->ncurves; j++) {
- *(pdh->y+j) = (NXCoord *)malloc( numpoints * sizeof(NXCoord) );
- }
- if (pdh->has_eybars) {
- pdh->ey = (NXCoord **)malloc( pdh->ncurves * sizeof(NXCoord *) );
- for (j = 0; j < pdh->ncurves; j++) {
- *(pdh->ey+j) = (NXCoord *)malloc( numpoints * sizeof(NXCoord) );
- }
- }
-
- pdh->npoints = numpoints;
-
- if (xdatathere) {
- NXRead(aDataStream, pdh->x, numpoints*sizeof(NXCoord));
- }
- else {
- for (j=0; j < numpoints; j++) {
- pdh->x[j] = (float)j;
- }
- }
- if (pdh->has_exbars) {
- NXRead(aDataStream, pdh->ex, numpoints*sizeof(NXCoord));
- }
- for (j = 0; j < pdh->ncurves; j++) {
- NXRead(aDataStream, *(pdh->y+j), numpoints*sizeof(NXCoord));
- if (pdh->has_eybars) {
- NXRead(aDataStream, *(pdh->ey+j), numpoints*sizeof(NXCoord));
- }
- }
-
- [self postludeToReading:fname :oldncurves :pdh];
-
- ncurvestotal += pdh->ncurves;
-
- return pdh->npoints;
- }
-
-
- - postludeToReading:(char *)fname :(int)oldncurves :(datahunk *)pdh
- {
- int j;
- float hue = 0.0;
- #define N_PREDEFINED_COLORS 9
- NXColor predefined_colors[] = {NX_COLORRED, NX_COLORGREEN, NX_COLORBLUE,
- NX_COLORCYAN, NX_COLORYELLOW, NX_COLORMAGENTA,
- NX_COLORORANGE, NX_COLORPURPLE, NX_COLORBROWN};
- // Those colors come from /usr/include/appkit/color.h
-
- /* Adjust the lineMatrix, symbolMatrix, and legendForm */
- [self adjustPanels:oldncurves :pdh->ncurves];
-
- if ([columnPanel isVisible])
- [columnSelectionHandler fixPanel:self];
-
- /*
- * Error bars don't get drawn unless the error bar matrix is correct.
- * Therefore we don't test on visibility here, rather we test on pdh itself.
- */
- if (pdh->has_exbars || pdh->has_eybars)
- [errorBarHandler updatePanel:self];
-
- if ([fileRemovalPanel isVisible])
- [self fixFileRemovalPanel:self];
-
- /* reset plot button */
- [plotButton setAltTitle:"Plotting"];
- [plotButton highlight:NO];
-
- [self findMinMax:pdh];
- /*
- * Don't bother to check lin/log unless this is the first file or
- * we already have at least one logarithmic axis:
- */
- if (nfilestotal==1 || [self xaxisLog] || [self yaxisLog] ) {
- [self checkLinLog:pdh];
- }
- else {
- pdh->xaxislin = YES;
- pdh->yaxislin = YES;
- }
-
- curvecolors = (NXColor *)realloc((void *)curvecolors,
- (ncurvestotal + pdh->ncurves) * sizeof(NXColor));
-
- [[canvas window] setTitleAsFilename:fname];
-
- if (!colorOption) {
- for (j=0; j<pdh->ncurves; j++) {
- curvecolors[j + ncurvestotal] = NX_COLORBLACK;
- }
- }
- else { /* adjust all the curve colors */
- // for (j=0; j<pdh->ncurves + ncurvestotal; j++) {
- // hue = 0.6667 * (float)((j+1) % MIN(11, ncurvestotal + pdh->ncurves))
- // / (float)MIN(10, ncurvestotal + pdh->ncurves);
- // curvecolors[j] = NXConvertHSBToColor(hue, 1.0, 1.0);
- // /* update curve no. on color panel */
- // [curveNumber setIntValue:j+1];
- // /* and update the color */
- // [curveColorWell setColor:curvecolors[j]];
- // }
- // The preceding has the unfortunate effect of changing colors on an already-plotted
- // curve if a new file is read in. This is undesirable. Here is a more
- // primitive method. Maybe a method based on (repeatable) random number
- // generation would be appropriate.
- // for (j=0; j<pdh->ncurves; j++) {
- // hue = 0.6667 * (float)((j+ncurvestotal+1) % 6) / 5.0;
- // curvecolors[j + ncurvestotal] = NXConvertHSBToColor(hue, 1.0, 1.0);
- // /* update curve no. on color panel */
- // [curveNumber setIntValue:j+ncurvestotal+1];
- // /* and update the color */
- // [curveColorWell setColor:curvecolors[j+ncurvestotal]];
- // }
- // All right, here is the method based on random numbers. Maybe this will be OK.
- // The trouble with it is that with srandom(10) [see above -- this was about
- // the best] the first two curves are about the same shade of green. Now the
- // strategy is to preset the first few curve colors, after that they will be
- // random.
- for (j=0; j<pdh->ncurves; j++) {
- if (j + ncurvestotal < N_PREDEFINED_COLORS) {
- curvecolors[j + ncurvestotal] = predefined_colors[j + ncurvestotal];
- }
- else {
- hue = 0.8 * ((float)random())/2147483647.0 ; /* 2^31 - 1 */
- curvecolors[j + ncurvestotal] = NXConvertHSBToColor(hue, 1.0, 1.0);
- }
- /* update curve no. on color panel */
- [curveNumber setIntValue:j+ncurvestotal+1];
- /* and update the color */
- [curveColorWell setColor:curvecolors[j+ncurvestotal]];
- }
- }
-
- return self;
- }
-
- - preludeToReading:(char *)fname :(datahunk **)pdh
- {
- datahunk dh;
-
- /* set plot button title "Reading" */
- [plotButton setAltTitle:"Reading"];
- [plotButton highlight:YES];
- NXPing(); /* force plotButton redraw */
-
- if (nfilestotal == 0) {
- datahunkArray = [Storage newCount:1
- elementSize:sizeof(datahunk)
- description:"{*{float *}{float *}{float **}{float **}iiffff{BOOL}{BOOL}{BOOL}{BOOL}}"];
- *pdh = (datahunk *)[datahunkArray elementAt:0];
- if (*pdh == NULL) {
- NXRunAlertPanel("readData",
- "Weird error 0: NULL pointer in readData\n"
- "I can't continue",
- "OK", NULL, NULL);
- exit(0);
- }
- nfilestotal = 1;
- }
- else {
- [datahunkArray addElement:(void *)&dh];
- *pdh = (datahunk *)[datahunkArray elementAt:(unsigned)nfilestotal];
- if (*pdh == NULL) {
- NXRunAlertPanel("readData",
- "Weird error 1: NULL pointer in readData\n"
- "I can't continue",
- "OK", NULL, NULL);
- exit(0);
- }
- nfilestotal++;
- }
- (*pdh)->filename = (char *)malloc(strlen(fname) + 1);
- strncpy((*pdh)->filename, fname, strlen(fname) + 1);
-
- (*pdh)->has_exbars = NO;
- (*pdh)->has_eybars = NO;
- if (strncmp([errorBars title], "y only", 6) == 0) {
- (*pdh)->has_eybars = YES;
- }
- else if (strncmp([errorBars title], "x only", 6) == 0) {
- (*pdh)->has_exbars = YES;
- }
- else if (strncmp([errorBars title], "x and y", 7) == 0) {
- (*pdh)->has_exbars = YES;
- (*pdh)->has_eybars = YES;
- }
-
- return self;
- }
-
- - plotPrepAndDraw
- {
- /* Check for linear or log on x and y axes */
- [self checkGlobalLinLog];
-
- [self findGlobalMinMax];
-
- /* Only check and reset min/max if this is the first file */
- if (nfilestotal == 1) {
- [self niceMinMaxInc];
- }
-
- [self drawPlot:self];
-
- return self;
- }
-
- - writeDataFiles:sender
- {
- int i, j, n;
- datahunk *pdh;
- NXStream *outputStream;
- char filename[1024], paneltitle[256];
- id savePanel = [[SavePanel new] setRequiredFileType:""];
-
- if (nfilestotal == 0) {
- NXRunAlertPanel("Write Data", "No data", "OK", NULL, NULL);
- }
- else {
- for (n=0; n<nfilestotal; n++) {
- pdh = (datahunk *)[datahunkArray elementAt:(unsigned)n];
- sprintf(paneltitle, "Save file %d (%s)", n+1,
- strrchr(pdh->filename,'/')==NULL ? pdh->filename
- : strrchr(pdh->filename,'/')+1);
- [savePanel setTitle:paneltitle];
- [savePanel setAccessoryView:writeDataAccButton];
- if ([savePanel runModal]) {
- strncpy(filename, [savePanel filename], 1024);
- if ((outputStream = NXOpenMemory(NULL, 0, NX_WRITEONLY)) == NULL) {
- NXRunAlertPanel("Write Data", "Cannot open memory for file %d",
- "OK", NULL, NULL, n);
- return self;
- }
- if ([writeDataAccButton state]) { /* ascii write */
- for (i=0; i<pdh->npoints; i++) {
- NXPrintf(outputStream, "%g", pdh->x[i]);
- if (pdh->has_exbars) {
- NXPrintf(outputStream, " %g", pdh->ex[i]);
- }
- for (j=0; j<pdh->ncurves; j++) {
- NXPrintf(outputStream, " %g", *(*(pdh->y+j)+i));
- if (pdh->has_eybars) {
- NXPrintf(outputStream, " %g", *(*(pdh->ey+j)+i));
- }
- }
- NXPrintf(outputStream, "\n");
- }
- }
- else { /* binary write */
- NXWrite(outputStream, pdh->x, (pdh->npoints)*sizeof(NXCoord));
- if (pdh->has_exbars) {
- NXWrite(outputStream, pdh->ex, (pdh->npoints)*sizeof(NXCoord));
- }
- for (j=0; j<pdh->ncurves; j++) {
- NXWrite(outputStream, *(pdh->y+j), (pdh->npoints)*sizeof(NXCoord));
- if (pdh->has_eybars) {
- NXWrite(outputStream, *(pdh->ey+j), (pdh->npoints)*sizeof(NXCoord));
- }
- }
- }
- NXFlush(outputStream);
- NXSaveToFile(outputStream, filename);
- NXClose(outputStream);
- }
- }
- }
- return self;
- }
-
- - whyTheBeep:sender
- {
- switch(beepError) {
- case 0:
- NXRunAlertPanel("The Beep Panel", "Press this button if the program beeps\n"
- "and you want to know why", "OK", NULL, NULL);
- break;
- case 1:
- NXRunAlertPanel("The Beep Happened Because:",
- "x-axis changed from log to linear", "OK", NULL, NULL);
- break;
- case 2:
- NXRunAlertPanel("The Beep Happened Because:",
- "y-axis changed from log to linear", "OK", NULL, NULL);
- break;
- case 3:
- NXRunAlertPanel("The Beep Happened Because:",
- "x-increment was negative\n (I changed it)", "OK", NULL, NULL);
- break;
- case 4:
- NXRunAlertPanel("The Beep Happened Because:",
- "xmax was less than xmin\n (I changed them)", "OK", NULL, NULL);
- break;
- case 5:
- NXRunAlertPanel("The Beep Happened Because:",
- "y-increment was negative\n (I changed it)", "OK", NULL, NULL);
- break;
- case 6:
- NXRunAlertPanel("The Beep Happened Because:",
- "ymax was less than ymin\n (I changed them)", "OK", NULL, NULL);
- break;
- case 7:
- NXRunAlertPanel("The Beep Happened Because:",
- "Too many tic marks would have been on the x-axis\n"
- " (I changed the min, max, and/or increment)",
- "OK", NULL, NULL);
- break;
- case 8:
- NXRunAlertPanel("The Beep Happened Because:",
- "Too many tic marks would have been on the y-axis\n"
- " (I changed the min, max, and/or increment)",
- "OK", NULL, NULL);
- break;
- case 9:
- NXRunAlertPanel("The Beep Happened Because:",
- "x-axis was logarithmic but some datum was negative\n"
- " (I changed x-axis to linear)", "OK", NULL, NULL);
- break;
- case 10:
- NXRunAlertPanel("The Beep Happened Because:",
- "y-axis was logarithmic but some datum was negative\n"
- " (I changed y-axis to linear)", "OK", NULL, NULL);
- break;
- case 11:
- NXRunAlertPanel("The Beep Happened Because:",
- "tried to set color of a non-existent curve", "OK", NULL, NULL);
- break;
- case 12:
- NXRunAlertPanel("The Beep Happened Because:",
- "an increment was too small for a log axis\n"
- " (I reset it)", "OK", NULL, NULL);
- break;
- }
- return self;
- }
-
- - (NXColor) provideBackgroundColor
- {
- if ( ( ([printPreview state] == 1) || (NXDrawingStatus == NX_PRINTING))
- && ([accPrintColorButton state] == 0) ) {
- return NX_COLORWHITE;
- }
- else {
- return backgroundcolor;
- }
- }
-
- - (NXColor) provideTextColor
- {
- if ( ( ([printPreview state] == 1) || (NXDrawingStatus == NX_PRINTING))
- && ([accPrintColorButton state] == 0) ) {
- return NX_COLORBLACK;
- }
- else {
- return textcolor;
- }
- }
-
- - (NXColor) provideCurveColor:(int)aCurve
- {
- if ( ( ([printPreview state] == 1) || (NXDrawingStatus == NX_PRINTING))
- && ([accPrintColorButton state] == 0) ) {
- return NX_COLORBLACK;
- }
- else {
- return curvecolors[aCurve];
- }
- }
-
- - setBackgroundColor:sender
- {
- backgroundcolor = [sender color];
- return self;
- }
-
- - forceBackgroundColor:(NXColor) aColor
- {
- backgroundcolor = aColor;
- return self;
- }
-
- - forceTextColor:(NXColor) aColor
- {
- textcolor = aColor;
- return self;
- }
-
- - forceCurveColor:(int)curvenum :(NXColor)aColor
- {
- if (curvenum >= ncurvestotal) {
- NXBeep();
- beepError = 11;
- }
- else {
- curvecolors[curvenum] = aColor;
- }
- return self;
- }
-
-
- - setTextColor:sender
- {
- textcolor = [sender color];
- return self;
- }
-
- - setCurveColor:sender
- {
- int curvenum = [curveNumber intValue];
-
- if (curvenum > ncurvestotal || curvenum < 1) {
- NXBeep();
- beepError = 11;
- return self;
- }
- /* Change the color in the color well right away: */
- [sender setColor:[sender color]];
- NXPing(); /* make sure it gets displayed */
- curvecolors[curvenum-1] = [sender color];
- /* Try to be helpful and increment the curvenumber */
- curvenum = (curvenum == ncurvestotal? 1 : curvenum + 1);
- /* Slight delay (1/2 second) so the well doesn't change instantly. */
- usleep((unsigned)500000);
- [curveNumber setIntValue:curvenum];
- /* Tell the sender (a color well) to go on the next color: */
- [sender setColor:curvecolors[curvenum - 1]];
- return self;
- }
-
- /* Update the curveColorWell if the curve number is changed */
- - textDidEnd:textObject endChar:(unsigned short)whyEnd
- {
- int curvenum = [curveNumber intValue];
- if (curvenum > ncurvestotal || curvenum < 1) {
- NXBeep();
- beepError = 11;
- return self;
- }
- [curveColorWell setColor:curvecolors[curvenum-1]];
- NXPing(); /* make sure it gets displayed */
- return self;
- }
-
- /* Update the global colorOption variable. */
- - colorOn:(BOOL)onOff
- {
- if (onOff) {
- colorOption = YES;
- backgroundcolor = NX_COLORBLACK;
- textcolor = NX_COLORWHITE;
- }
- else {
- colorOption = NO;
- backgroundcolor = NX_COLORWHITE;
- textcolor = NX_COLORBLACK;
- }
- [textColorWell setColor:textcolor];
- [backgroundColorWell setColor:backgroundcolor];
- [curveColorWell setColor:textcolor];
-
- return self;
- }
-
- - fixMatrixColumn:sender /* The sender is a matrix */
- {
- int row, col, i;
-
- row = [sender selectedRow];
- col = [sender selectedCol];
- if (sender == lineMatrix) {
- [self adjustLineStyleMatrix:col :row];
- // Now, instead of redisplaying the whole matrix, just redraw the
- // cells in the affected column. It's much faster this way.
- for (i=0; i<N_LINE_STYLES; i++)
- [lineMatrix drawCellAt:i :col];
- }
- else if (sender == symbolMatrix) {
- [self adjustSymbolTypeMatrix:col :row];
- // Comment above applies here, too.
- for (i=0; i<N_SYMBOL_STYLES; i++)
- [symbolMatrix drawCellAt:i :col];
- }
- return self;
- }
-
- /* change the column which is to be taken as the x data */
- - swapColumns:(int)prev_col :(int)col forFileNumber:(int)i
- {
- datahunk *pdh;
- float *tmp;
-
- if (col < 0 || prev_col < 0) /* be very cautious */
- return self;
-
- if (col==0 && prev_col==0) /* must avoid this special case */
- return self;
-
- pdh = (datahunk *)[datahunkArray elementAt:(unsigned)i];
- if (prev_col == 0) { /* was first column, generic x-data */
- // tmp = pdh->x; /* why doesn't this order work? */
- // pdh->x = *(pdh->y + col-1);
- // *(pdh->y + col-1) = tmp;
- tmp = *(pdh->y + col-1);
- *(pdh->y + col-1) = pdh->x;
- pdh->x = tmp;
- }
- else if (col == 0) { /* revert back to generic x-data */
- tmp = *(pdh->y + prev_col - 1);
- *(pdh->y + prev_col - 1) = pdh->x;
- pdh->x = tmp;
- }
- else { /* swapping y's only */
- tmp = *(pdh->y + prev_col - 1);
- *(pdh->y + prev_col - 1) = *(pdh->y + col - 1);
- *(pdh->y + col - 1) = tmp;
- }
-
- [self findMinMax:pdh]; /* reset these values here */
- [self findGlobalMinMax];
-
- return self;
- }
-
-
- /*
- * This function is called by the PlotView object during zooming.
- */
- - stackOldMinMax:(float)xmin :(float)xmax :(float)ymin :(float)ymax
- {
- oldMin = currentMin; /* structure assignment */
- oldMax = currentMax;
- oldInc = currentInc; /* have to deal with the increments, too */
- currentMin.x = xmin;
- currentMax.x = xmax;
- currentMin.y = ymin;
- currentMax.y = ymax;
- currentInc.x = [xInc floatValueAt:0];
- currentInc.y = [yInc floatValueAt:0];
-
- return self;
- }
-
- /*
- * This method is invoked by the "Previous View" button on the
- * control panel.
- */
- - previousView:sender
- {
- NXPoint tmp;
-
- [self resetXmin:(double)oldMin.x];
- [self resetXmax:(double)oldMax.x];
- [self resetXinc:(double)oldInc.x];
- [self resetYmin:(double)oldMin.y];
- [self resetYmax:(double)oldMax.y];
- [self resetYinc:(double)oldInc.y];
- tmp = oldMin;
- oldMin = currentMin;
- currentMin = tmp;
- tmp = oldMax;
- oldMax = currentMax;
- currentMax = tmp;
- tmp = oldInc;
- oldInc = currentInc;
- currentInc = tmp;
- [self drawPlotButton:1]; /* display "Plotting" */
- [canvas display];
- [self drawPlotButton:0]; /* display "Plot" */
-
- return self;
- }
-
- @end
-